package pl.mdziedzic.unittests.basics;

import static org.fest.assertions.Assertions.assertThat;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;

import pl.mdziedzic.unittests.services.HistoryChange;
import pl.mdziedzic.unittests.services.HistoryCollector;
import pl.mdziedzic.unittests.services.HistoryProvider;
import pl.mdziedzic.unittests.services.MAIL_TEMPLATE;
import pl.mdziedzic.unittests.services.MailProvider;
import pl.mdziedzic.unittests.services.RequestContext;
import pl.mdziedzic.unittests.services.SimpleHistoryProvider;

public class MockitoSamples {

	RequestContext context;

	@Before
	public void init() {
		context = mock(RequestContext.class);
	}

	@Test
	public void shouldStubReturnValue() {
		MailProvider mockedProvider = mock(MailProvider.class);
		when(context.getMailProvider()).thenReturn(mockedProvider);

		MailProvider mailProvider = context.getMailProvider();
		assertThat(mailProvider).isEqualTo(mockedProvider);
	}

	@Test(expected = RuntimeException.class)
	public void shouldThrowExceptionWhenCalled() {
		when(context.getMailProvider()).thenThrow(new RuntimeException());

		context.getMailProvider();
	}

	@Test(expected = RuntimeException.class)
	public void shouldStabVoidMethod() {
		MailProvider mailProvider = mock(MailProvider.class);
		doThrow(new RuntimeException()).when(mailProvider).sendMail(MAIL_TEMPLATE.YOU_BOUGHT_AUCTION);

		mailProvider.sendMail(MAIL_TEMPLATE.YOU_BOUGHT_AUCTION);
	}

	@Test
	public void shouldUseMatcherToReturnCorrectValue() {
		HistoryProvider historyProvider = mock(HistoryProvider.class);
		HistoryCollector historyCollector = mock(HistoryCollector.class);

		when(historyProvider.getHistory(anyString())).thenReturn(historyCollector);

		HistoryCollector stringHistory = historyProvider.getHistory("Historia stringa");
		assertThat(stringHistory).isEqualTo(stringHistory);
	}
	
	@Test
	public void shouldVerifyMethodWasCalled() {
		context.getMailProvider();

		verify(context).getMailProvider();
	}

	@Test
	public void shouldVerifyExactNumberOfInvocations() {
		context.getMailProvider();
		context.getMailProvider();

		verify(context, never()).getHistoryProvider();
		verify(context, times(2)).getMailProvider();
	}

	@Test
	public void shouldCaptureHistoryChange() {
		// given
		HistoryCollector collector = mock(HistoryCollector.class);
		SimpleHistoryProvider provider = new SimpleHistoryProvider(collector);
		
		// when
		provider.collect("Old Value", "New Value");
		
		// then
		ArgumentCaptor<HistoryChange> captor = ArgumentCaptor.forClass(HistoryChange.class);
		verify(collector).collect(captor.capture());
		
		HistoryChange historyChange = captor.getValue();
		
		assertThat(historyChange.getOldValue()).isEqualTo("Old Value");
		assertThat(historyChange.getNewValue()).isEqualTo("New Value");
	}

}
